﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;

using Fennec;

namespace IHM
{
    public partial class FenetreJeu : Window
    {

/*****************************************************************************************/
    // Attributs
    // tous ces attributs peuvent (ou devraient) être reconstruits depuis le modèle au constructeur
    // intérêt : sauvegarder et charger le modèle et pas la vue
        // Basiques
            public IHMPartie partie;
            public int cote;

        // Attributs graphiques
            public SolidColorBrush[] couleurs; // tableau de couleurs, 1 civilisation -> 1 couleur
            public Code.IHMCase[,] casesIHM;
            public bool[,] casesVisibles;
            public int[,] nombreVoyeurs;

        // Actions
            
            public System.Windows.Media.Brush couleurBoutonInitiale;
            public bool actionAllerCommencée;
            public List<System.Drawing.Point> listeCasesAColorer;

            public bool actionCommencee;
            public System.Drawing.Point anciennePosition;
                // Fleches
                public EDirection direction;

        // Classes méthode
            // On ne laisse dans cette classe que les fonctions qui sont appelées par Xaml directement ou indirectement
            public ClassesFonction.ConstructeurGraphique constructeurGraphique;
            public ClassesFonction.ReactionEvenementBandeauHaut reactionEvenementBandeauHaut;
            public ClassesFonction.ReactionEvenementBandeauBas reactionEvenementBandeauBas;
            public ClassesFonction.ReactionEvenementCarte reactionEvenementCarte;
            public ClassesFonction.ReactionEvenementInitialisation reactionEvenementInitialisation;

/*****************************************************************************************/

    // Constructeurs et initialisation
        // Constructeur indépendant des fenêtres précédentes [TEMPORAIRE]

        public FenetreJeu()
        {
            // Initialisation des attributs d'une PartieIHM pour tester [TEMPORAIRE]
                ECarteTaille taille = new ECarteTaille();
                taille = ECarteTaille.CARTE_TAILLE_NORMALE;

                IHMCivilisation[] civilisations = new IHMCivilisation[3];
                civilisations[0] = new IHMCivilisation();
                civilisations[1] = new IHMCivilisation();
                civilisations[2] = new IHMCivilisation();

                civilisations[0].civilisation = ECivilisationNom.CIVILISATION_EII;
                civilisations[1].civilisation = ECivilisationNom.CIVILISATION_INFO;
                civilisations[2].civilisation = ECivilisationNom.CIVILISATION_INFO;

                civilisations[0].couleur = ECouleur.COLOR_RED;
                civilisations[1].couleur = ECouleur.COLOR_BLUE;
                civilisations[2].couleur = ECouleur.COLOR_GREEN;

                civilisations[0].nom = "Jean";
                civilisations[1].nom = "Naji";
                civilisations[2].nom = "Pierre";
                
            InitializeComponent();

            // Global
            partie = new IHMPartie(taille, civilisations);
            cote = partie.carte.getDimensions().X;

            //Observateur
                partie.observable += new ChangedEventHandler(this.traiterEvenement);

            // Initialisation des attributs d'une PartieIHM pour tester [TEMPORAIRE]
                partie.unités_sélectionnées = new Dictionary<int,Unité>();
            
            //Actions
                couleurBoutonInitiale = infoActionAller.Background;
                actionCommencee = false;
                listeCasesAColorer = new List<System.Drawing.Point>(); 
                direction = EDirection.DIR_NULL;

                casesIHM = new Code.IHMCase[cote, cote];
                casesVisibles = new bool[cote,cote];
                nombreVoyeurs = new int[cote, cote];

            //Classes fonction
                constructeurGraphique = new ClassesFonction.ConstructeurGraphique(this);
                reactionEvenementBandeauHaut = new ClassesFonction.ReactionEvenementBandeauHaut(this);
                reactionEvenementBandeauBas = new ClassesFonction.ReactionEvenementBandeauBas(this);
                reactionEvenementCarte = new ClassesFonction.ReactionEvenementCarte(this);
                reactionEvenementInitialisation = new ClassesFonction.ReactionEvenementInitialisation(this);

            //Initialisation des premiers éléments graphiques
                couleurs = new SolidColorBrush[4];
                reactionEvenementInitialisation.evenementChargementVue(); // du type IHM -> IHM
        }

        // Véritable constructeur
        public FenetreJeu(ECarteTaille taille, IHMCivilisation[] c)
        {
            InitializeComponent();

            // Global
            partie = new IHMPartie(taille, c);
            cote = (partie.carte.getDimensions().X);

            //Observateur
            partie.observable += new ChangedEventHandler(this.traiterEvenement);

            //Actions
                couleurBoutonInitiale = infoActionAller.Background;
                actionCommencee = false;
                listeCasesAColorer = new List<System.Drawing.Point>(); 
                direction = EDirection.DIR_NULL;

                casesIHM = new Code.IHMCase[cote, cote];
                casesVisibles = new bool[cote,cote];
                nombreVoyeurs = new int[cote, cote];
            
            //Classes fonction
                constructeurGraphique = new ClassesFonction.ConstructeurGraphique(this);
                reactionEvenementBandeauHaut = new ClassesFonction.ReactionEvenementBandeauHaut(this);
                reactionEvenementBandeauBas = new ClassesFonction.ReactionEvenementBandeauBas(this);
                reactionEvenementCarte = new ClassesFonction.ReactionEvenementCarte(this);
                reactionEvenementInitialisation = new ClassesFonction.ReactionEvenementInitialisation(this);

            //Initialisation des premiers éléments graphiques
                couleurs = new SolidColorBrush[4];
                reactionEvenementInitialisation.evenementChargementVue(); // du type IHM -> IHM
        }

        // Constructeur avec une partie chargée
        public FenetreJeu(IHMPartie p)
        {
            InitializeComponent();

            // Global
            // création d'une partie vide, afin de la remplir avec les attributs de p
            partie = new IHMPartie();

            partie.action_preparee = p.action_preparee;
            partie.carte = p.carte;
            partie.civilisations = p.civilisations;
            partie.civilisation_courante = p.civilisation_courante;
            partie.couleurs = p.couleurs;
            partie.noms = p.noms;
            partie.num_tour = p.num_tour;
            partie.partie_finie = p.partie_finie;
            partie.partie_initialisée = p.partie_initialisée;
            partie.position_sélectionnée = p.position_sélectionnée;
            partie.unité_selectionnée = p.unité_selectionnée;
            partie.unités_sélectionnées = p.unités_sélectionnées;
            partie.vainqueur = p.vainqueur;
            partie.ville_selectionnée = p.ville_selectionnée;

            cote = partie.carte.getDimensions().X;

            //Observateur
            partie.observable += new ChangedEventHandler(this.traiterEvenement);

            //Actions
            couleurBoutonInitiale = infoActionAller.Background;
            actionCommencee = false;
            listeCasesAColorer = new List<System.Drawing.Point>();
            direction = EDirection.DIR_NULL;

            casesIHM = new Code.IHMCase[cote, cote];
            casesVisibles = new bool[cote, cote];
            nombreVoyeurs = new int[cote, cote];

            //Classes fonction
            constructeurGraphique = new ClassesFonction.ConstructeurGraphique(this);
            reactionEvenementBandeauHaut = new ClassesFonction.ReactionEvenementBandeauHaut(this);
            reactionEvenementBandeauBas = new ClassesFonction.ReactionEvenementBandeauBas(this);
            reactionEvenementCarte = new ClassesFonction.ReactionEvenementCarte(this);
            reactionEvenementInitialisation = new ClassesFonction.ReactionEvenementInitialisation(this);

            //Initialisation des premiers éléments graphiques
            couleurs = new SolidColorBrush[4];
            reactionEvenementInitialisation.evenementChargementVue(); // du type IHM -> IHM
        }

        /*******************************/

        public void traiterEvenement(object sender, EventArgs ev)
        {
            switch (((Evenement)ev).evenement)
            {
                case Enumerations.EEvenement.EV_CHARGEMENT_VUE:
                    reactionEvenementInitialisation.evenementChargementVue();
                    break;
                case Enumerations.EEvenement.EV_ACTION_ALLER:
                    reactionEvenementCarte.evenementCarteActionVue(Enumerations.EAction.ACTION_ALLER);
                    break;
                case Enumerations.EEvenement.EV_ACTION_ATTAQUER:
                    reactionEvenementCarte.evenementCarteActionVue(Enumerations.EAction.ACTION_ATTAQUER);
                    break;
                case Enumerations.EEvenement.EV_TOUR_SUIVANT:
                    reactionEvenementBandeauHaut.evenementHautTourSuivant();
                    break;
                case Enumerations.EEvenement.EV_ENSEIGNANT:
                    reactionEvenementBandeauHaut.evenementHautNombreEnseignants();
                    break;
                case Enumerations.EEvenement.EV_ETUDIANT:
                    reactionEvenementBandeauHaut.evenementHautNombreEtudiants();
                    break;
                case Enumerations.EEvenement.EV_DIRECTEUR:
                    reactionEvenementBandeauHaut.evenementHautDirecteur();
                    break;
                case Enumerations.EEvenement.EV_VILLE:
                    reactionEvenementBandeauHaut.evenementHautNombreVilles();
                    break;
                case Enumerations.EEvenement.EV_CIVILISATION:
                    reactionEvenementBandeauHaut.evenementHautCivilisationMorte();
                    break;
                case Enumerations.EEvenement.EV_CLIC_SUR_CASE:
                    reactionEvenementBandeauBas.evenementBasClicSurCase();
                    break;
                case Enumerations.EEvenement.EV_VILLE_MODIFIEE:
                    reactionEvenementBandeauBas.evenementBasVilleModifiee();
                    break;
                case Enumerations.EEvenement.EV_UNITE_SELECTIONNEE_OU_MODIFIEE:
                    reactionEvenementBandeauBas.evenementBasUniteSelectionneeOuModifiee();
                    break;
                case Enumerations.EEvenement.EV_VILLE_CREEE:
                    reactionEvenementCarte.evenementCarteAjouterVille(partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
                    break;
                case Enumerations.EEvenement.EV_ET_CREE:
                    reactionEvenementCarte.evenementCarteAjouterUnite(EElement.EL_ET, partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
                    break;
                case Enumerations.EEvenement.EV_ENS_CREE:
                    reactionEvenementCarte.evenementCarteAjouterUnite(EElement.EL_ENS, partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
                    break;
                case Enumerations.EEvenement.EV_DIR_CREE:
                    reactionEvenementCarte.evenementCarteAjouterUnite(EElement.EL_DIR, partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
                    break;
                case Enumerations.EEvenement.EV_VILLE_DETRUITE:
                    reactionEvenementCarte.evenementCarteVilleDetruite(partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
                    break;
                case Enumerations.EEvenement.EV_ET_TUE:
                    reactionEvenementCarte.evenementCarteUniteTuee(EElement.EL_ET, partie.position_sélectionnée.X, partie.position_sélectionnée.Y);
                    break;
                case Enumerations.EEvenement.EV_ENS_TUE:
                    reactionEvenementCarte.evenementCarteUniteTuee(EElement.EL_ENS, partie.position_sélectionnée.X, partie.position_sélectionnée.Y);
                    break;
                case Enumerations.EEvenement.EV_DIR_TUE:
                    reactionEvenementCarte.evenementCarteUniteTuee(EElement.EL_DIR, partie.position_sélectionnée.X, partie.position_sélectionnée.Y);
                    break;
            }
        }
        /******************************/
        
        // Création de la carte, appelé par le code xaml à l'initialisation indépendement du constructeur
        public void Carte(object sender, RoutedEventArgs e)
        {
            //int cote = partie.carte.getDimensions().X; TODO : à résoudre
            int cote = (partie.carte.taille.Equals(ECarteTaille.CARTE_TAILLE_PETITE)) ? 25 : 100;

            for (int c1 = 0; c1 < cote; c1++)
            {
                infoGridCarte.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50, GridUnitType.Pixel) });
            }

            for (int c2 = 0; c2 < cote; c2++)
            {
                infoGridCarte.RowDefinitions.Add(new RowDefinition { Height = new GridLength(50, GridUnitType.Pixel) });
            }

            for (int c1 = 0; c1 < cote; c1++)
            {
                for (int c2 = 0; c2 < cote; c2++)
                {
                    Case c = partie.carte.getCase(new System.Drawing.Point(c1, c2));

                    /*
                    // Carte aléatoire pour tester [TEMPORAIRE]
                    Random random0 = new Random();
                    // int n = random0.Next(0, 1); // Random super-temporaire, test pour les cases "atteignables"
                    int n = random0.Next(0, 9);

                    Case c = null;

                    switch (n)
                    {
                        case 0:
                            c = new CaseMontagne();
                            break;
                        case 1:
                            c = new CaseDésert();
                            break;
                        case 2:
                            c = new CasePlaine();
                            break;
                        case 3:
                            c = new CaseFer(new CaseMontagne());
                            break;
                        case 4:
                            c = new CaseFer(new CaseDésert());
                            break;
                        case 5:
                            c = new CaseFer(new CasePlaine());
                            break;
                        case 6:
                            c = new CaseFruit(new CaseMontagne());
                            break;
                        case 7:
                            c = new CaseFruit(new CaseDésert());
                            break;
                        case 8:
                            c = new CaseFruit(new CaseMontagne());
                            break;
                    }
                    */

                    if (c != null)
                    {
                        Rectangle r = creerRectangleCase(c1, c2, c);

                        casesIHM[c1,c2] = new Code.IHMCase();
                        casesIHM[c1,c2].rectangleCase = r;
                        casesIHM[c1,c2].ville = constructeurGraphique.creerEllipseVille(c1, c2);
                        casesIHM[c1, c2].etudiants = constructeurGraphique.creerTextBlockUnite(c1, c2, EElement.EL_ET);
                        casesIHM[c1, c2].enseignants = constructeurGraphique.creerTextBlockUnite(c1, c2, EElement.EL_ENS);
                        casesIHM[c1, c2].directeur = constructeurGraphique.creerTextBlockUnite(c1, c2, EElement.EL_DIR);

                        infoGridCarte.Children.Add(r);
                    }
                }
            }

            reactionEvenementInitialisation.brouillardDeGuerre();
        }

        // Fonction qui créé un rectangle de type case, ce rectangle est associé à la case en question via l'attribut Tag
        // Ne peut être ajouté au constructeur graphique à cause de l'appel particulier à r_MouseLeftButtonDown
        public Rectangle creerRectangleCase(int c1, int c2, Case c)
        {
            Rectangle r = new Rectangle();

            if (c is CaseDésert)
            {
                r.Fill = Brushes.Yellow;
            }

            if (c is CasePlaine)
            {
                r.Fill = Brushes.Green;
            }

            if (c is CaseMontagne)
            {
                r.Fill = Brushes.Brown;
            }

            if (c is CaseFer)
            {
                if (((CaseDécorateur)c).case_brute is CaseDésert)
                {
                    r.Fill = Brushes.PaleGoldenrod;
                }

                if (((CaseDécorateur)c).case_brute is CasePlaine)
                {
                    r.Fill = Brushes.DarkSeaGreen;
                }

                if (((CaseDécorateur)c).case_brute is CaseMontagne)
                {
                    r.Fill = Brushes.DimGray;
                }
            }

            if (c is CaseFruit)
            {
                if (((CaseDécorateur)c).case_brute is CaseDésert)
                {
                    r.Fill = Brushes.LightPink;
                }

                if (((CaseDécorateur)c).case_brute is CasePlaine)
                {
                    r.Fill = Brushes.HotPink;
                }

                if (((CaseDécorateur)c).case_brute is CaseMontagne)
                {
                    r.Fill = Brushes.RosyBrown;
                }
            }

            Grid.SetColumn(r, c1);
            Grid.SetRow(r, c2);

            r.Stroke = Brushes.Black;
            r.Tag = c;

            r.MouseLeftButtonDown += new MouseButtonEventHandler(r_MouseLeftButtonDown);

            return r;
        }

        // Clic sur une case de la carte
        void r_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Rectangle r = sender as Rectangle;

            if (actionAllerCommencée)
            {
                anciennePosition = partie.position_sélectionnée;
            }

            partie.setPoint(Grid.GetColumn(r), Grid.GetRow(r));  // Attention : au clic sur une case on ne veut pas toujours changer la position sélectionnée (exemple : lors d'une attaque ou on choisit sa cible)

            reactionEvenementBandeauBas.evenementBasClicSurCase();// du type IHM -> IHM
        } 
       
    // Gestion des boutons
    // Utilisés pour les test : lancent évènement et ne touchent pas au modèle, à l'exception de ClickFin [TEMPORAIRE]

        // Fin de tour
        public void ClickFin(object sender, RoutedEventArgs e)
        {
            if (System.Windows.Forms.MessageBox.Show("Certain ?", null, MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                partie.tourSuivant();
            }
        }

        // Ne fonctionne pas, fichier xml quasi vide
        public void ClickSauvegarde(object sender, RoutedEventArgs e)
        {
            SaveFileDialog boiteSauvegarde = new SaveFileDialog();
            boiteSauvegarde.Filter = "Fichier xml(*.xml)|*.xml";

            if (boiteSauvegarde.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                FileStream file = File.Open(boiteSauvegarde.FileName, FileMode.OpenOrCreate);
                XmlSerializer ser = new XmlSerializer(typeof(IHMPartie));  // using System.Xml.Serialization;
                ser.Serialize(file, partie);
                file.Close();
            }
        }

        public void ClickUnité(object sender, EventArgs e)
        {
            Unité u = (Unité)((System.Windows.Controls.Button)sender).Tag;

            foreach (KeyValuePair<int, Unité> kvp in partie.unités_sélectionnées)
            {
                if (u.Equals(kvp.Value))
                {
                    partie.sélectionnerUnité(kvp.Key);
                }
            }

            reactionEvenementBandeauBas.evenementBasUniteSelectionneeOuModifiee(); // réaction du type IHM -> IHM
        }

        public void ClickActionAller(object sender, RoutedEventArgs e)
        {
            if (!actionAllerCommencée)
            {
                actionAllerCommencée = true;

                // [TEMPORAIRE]
                System.Drawing.Point p = new System.Drawing.Point(5, 5);
                partie.unités_sélectionnées[partie.unité_selectionnée] = new UnitéEtudiant(p);
                reactionEvenementCarte.evenementCarteAjouterUnite(EElement.EL_ET, partie.position_sélectionnée.X, partie.position_sélectionnée.Y, partie.civilisation_courante);
            }
            reactionEvenementCarte.evenementCarteActionVue(Enumerations.EAction.ACTION_ALLER);// réaction du type IHM -> IHM
        }

        public void ClickActionAttaquer(object sender, RoutedEventArgs e)
        {
            
        }

        public void ClickActionFonder(object sender, RoutedEventArgs e)
        {
            
        }

        public void ClickActionCreerEt(object sender, RoutedEventArgs e)
        {
            
        }

        public void ClickActionCreerEns(object sender, RoutedEventArgs e)
        {
                        
        }

        public void ClickActionCreerDir(object sender, RoutedEventArgs e)
        {
            
        }

        // Appui sur une touche du clavier
        private void window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (actionCommencee)
            {
                switch (e.Key)
                {
                    case Key.Up:
                        direction = EDirection.DIR_HAUT;
                        break;
                    case Key.Down:
                        direction = EDirection.DIR_BAS;
                        break;
                    case Key.Left:
                        direction = EDirection.DIR_GAUCHE;
                        break;
                    case Key.Right:
                        direction = EDirection.DIR_DROITE;
                        break;
                    default:
                        break;
                }
            }

            if (actionAllerCommencée)
            {
                anciennePosition = partie.position_sélectionnée;

                switch (direction)
                {
                    case EDirection.DIR_HAUT:
                        partie.setPoint(partie.position_sélectionnée.X, partie.position_sélectionnée.Y - 1);
                        break;
                    case EDirection.DIR_BAS:
                        partie.setPoint(partie.position_sélectionnée.X, partie.position_sélectionnée.Y + 1);
                        break;
                    case EDirection.DIR_GAUCHE:
                        partie.setPoint(partie.position_sélectionnée.X - 1, partie.position_sélectionnée.Y);
                        break;
                    case EDirection.DIR_DROITE:
                        partie.setPoint(partie.position_sélectionnée.X + 1, partie.position_sélectionnée.Y);
                        break;
                }

                reactionEvenementBandeauBas.evenementCarteActionAller();
            }
        }
    }
}